package com.nsu.konus.control;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;

import com.nsu.konus.control.preferences.KonusPreference;

public class ControlManager {
	
	private static ControlManager singleton;
	
	private ControlManager() {
	}
	
	public static ControlManager getInstance() throws IOException, InterruptedException {
		if (singleton == null) {
			singleton = new ControlManager();
			singleton.start();
		}
		return singleton;
	}
	
	public String compileFortranFile(String fortranSourcePath) throws IOException, InterruptedException {
		File f = new File(fortranSourcePath);
		String path = f.getParent();
		String fortranSourceName = f.getName();
		KonusPreference pref = KonusPreference.getInstance();
		String konusPath = pref.getKonusPath();
		//set directory with source file to C
		sender.mount("c", konusPath);
		
		//set directory with Fortran to D
		String fortranPath = pref.getFortranPath();
		String dir = new File(fortranPath, "BINB").getPath();
		sender.mount("d", dir);
		sender.sendString("C:");
		
		copyFile(fortranSourcePath, new File(konusPath,
				fortranSourceName).getAbsolutePath());
		
		String name = StringUtils.getFileName(fortranSourceName);
		//String konusPath = KonusPreference.getInstance().getKonusPath();
		sender.sendStringWithSleep(20000, "D:\\FL /AH /FPi87 /c " + fortranSourceName);
		sender.sendStringWithSleep(1000, "D:\\LIB " + name + " +" + name + " " + name + ".lst");
		sender.sendStringWithSleep(1000, "file");
		sender.sendStringWithSleep(1000, "file");
		FileWriter writer = new FileWriter(new File(konusPath, name + ".lnk"));
		writer.write(
				"/noe /nod /SE:320 /STACK:6144 /exepack " + name + " +\n" + 
				"( c:\\lnsm-obj\\linsimbg c:\\lnsm-obj\\memread ) +\n" +
				"( c:\\dial-obj\\dialog c:\\dial-obj\\basis +\n" +
				"  c:\\dial-obj\\bndlin c:\\dial-obj\\filer +\n" +
				"  c:\\dial-obj\\graph  c:\\dial-obj\\tablscr ) +\n" +
				"( c:\\solv-obj\\solver1 c:\\solv-obj\\solver2 +\n" +
				"  c:\\solv-obj\\algebr1 c:\\solv-obj\\algebr2 +\n" +
				"  c:\\solv-obj\\invert  c:\\solv-obj\\kvasinew +\n" +
				"  c:\\solv-obj\\lagrange )\n" +
				"  " + name + ".exe\n" +
				"  NUL\n" +
				"  " + name + ".lib dolly c:\\root-obj\\root graphics llibfor7;\n");
		writer.close();
		sender.sendStringWithSleep(3000, "D:\\LINK @" + name + ".lnk");
		sender.sendStringWithSleep(1000, "file");
		sender.sendStringWithSleep(60000, "file");
		sender.sendString("Z:");
		sender.remount("c");
		sender.remount("d");

		copyFile(new File(konusPath, name + ".exe").getAbsolutePath(),
				new File(path, name + ".exe").getAbsolutePath());
		
		return name;
	}
	
	public String runSolver(String solverPath, String dataPath) throws IOException, InterruptedException {
		File solver = new File(solverPath);
		File data = new File(dataPath);
		String konusPath = KonusPreference.getInstance().getKonusPath();
		sender.mount("c", konusPath);
		sender.mount("d", data.getParent());
		sender.sendString("C:");
		
		copyFile(solverPath, new File(konusPath,
				solver.getName()).getAbsolutePath());
		
		sender.sendString(solver.getName() + " D:\\" + data.getName());
		//wait, while solver start work
		Thread.sleep(5000);
		//start solving
		sender.run("enter");
		//wait, while solver working
		Thread.sleep(KonusPreference.getInstance().getSolverWorkingTime() * 1000);
		//stop solving
		sender.sendWithSleep(5000, "f10");
		//wait, while solver stopped
		//any key
		
		String resultFileName = "result.txt";
		
		//delete result file, if it exist
		File resultFile = new File(KonusPreference.getInstance().getKonusPath(), resultFileName);
		if (resultFile.exists()) {
			resultFile.delete();
		}
		
		sender.sendWithSleep(3000, "enter");
		sender.sendWithSleep(1000, "left");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "down");
		sender.sendWithSleep(100, "down");
		sender.sendWithSleep(100, "down");
		sender.sendWithSleep(100, "enter");
		sender.sendString(resultFileName);
		Thread.sleep(500);
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(3000, "f1");
		sender.sendWithSleep(100, "enter");
		sender.sendWithSleep(100, "esc");
		sender.sendWithSleep(100, "right");
		sender.sendWithSleep(100, "right");
		sender.sendWithSleep(1000, "enter");
		sender.sendString("Z:");
		sender.remount("c");
		sender.remount("d");

		copyFile(new File(konusPath, resultFileName).getAbsolutePath(),
				new File(solver.getParent(), resultFileName).getAbsolutePath());
		
		return resultFileName;
	}
	
	private void start() throws IOException, InterruptedException {
		createBatFile();
		runDosbox();
		Thread.sleep(1000);
		runRussifier();
	}
	
	private void createBatFile() throws IOException {
		FileWriter writer = new FileWriter("run.bat");
		writer.write("start " + KonusPreference.getInstance().getDosboxPath());
		writer.close();
	}
	
	private void runDosbox() throws UnknownHostException, IOException, InterruptedException {
		if (sender == null) {
			sender = new KonusSender();
			sender.start();
			runDosboxProcess();
			sender.findDosboxClient();
		}
	}
	
	private void runDosboxProcess() throws IOException {
        Runtime runtime = Runtime.getRuntime();
        runtime.exec(new String[] {"run.bat"});
	}
	
	private void runRussifier() throws IOException, InterruptedException {
		sender.mount("y", KonusPreference.getInstance().getRussifierPath());
		sender.run("y:\\rk.com");
		sender.remount("y");
	}
	
    private void copyFile(String src, String dst) throws IOException {
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dst);
    
        // Transfer bytes from in to out
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }
	
	private KonusSender sender;
	/*
	private int port = 7788;
	*/
}
